//! 调度策略实现
//! 
//! 提供多种智能调度策略

use std::collections::HashMap;
use std::time::Duration;
use async_trait::async_trait;
use serde::{Serialize, Deserialize};

use crate::scheduler::scheduler::{SchedulingRequest, NodeInfo};
use crate::types::{Language, Priority, ResourceRequirements, PoolType};

/// 调度策略特征
#[async_trait]
pub trait SchedulingPolicy: Send + Sync {
    /// 策略名称
    fn name(&self) -> &str;
    
    /// 策略描述
    fn description(&self) -> &str;
    
    /// 做出调度决策
    async fn make_decision(&self, context: &SchedulingContext) -> PolicyDecision;
    
    /// 策略优先级（数值越高优先级越高）
    fn priority(&self) -> u32 {
        100
    }
    
    /// 是否支持指定的语言
    fn supports_language(&self, language: &Language) -> bool {
        true
    }
    
    /// 策略配置
    fn configure(&mut self, config: HashMap<String, String>) -> anyhow::Result<()> {
        Ok(())
    }
}

/// 调度上下文
#[derive(Debug, Clone)]
pub struct SchedulingContext {
    /// 调度请求
    pub request: SchedulingRequest,
    /// 可用资源
    pub available_resources: HashMap<String, ResourceRequirements>,
    /// 当前系统负载
    pub current_load: f64,
    /// 节点约束
    pub node_constraints: Vec<NodeConstraint>,
}

/// 节点约束
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeConstraint {
    /// 约束类型
    pub constraint_type: ConstraintType,
    /// 约束值
    pub value: String,
    /// 是否为硬约束
    pub hard: bool,
}

/// 约束类型
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ConstraintType {
    /// 区域约束
    Zone,
    /// 实例类型约束
    InstanceType,
    /// 标签约束
    Label,
    /// 资源约束
    Resource,
}

/// 策略决策
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyDecision {
    /// 调度动作
    pub action: SchedulingAction,
    /// 决策置信度（0.0-1.0）
    pub confidence: f64,
    /// 决策原因
    pub reason: String,
    /// 备选方案
    pub alternatives: Vec<SchedulingAction>,
    /// 决策时间
    pub decision_time: Duration,
}

impl Default for PolicyDecision {
    fn default() -> Self {
        Self {
            action: SchedulingAction::Reject { reason: "无策略决策".to_string() },
            confidence: 0.0,
            reason: "默认决策".to_string(),
            alternatives: Vec::new(),
            decision_time: Duration::from_millis(0),
        }
    }
}

/// 调度动作
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SchedulingAction {
    /// 分配资源
    Allocate {
        /// 池类型
        pool_type: PoolType,
        /// 节点偏好
        node_preference: Option<NodeInfo>,
    },
    /// 加入队列等待
    Queue {
        /// 预计等待时间
        estimated_wait_time: Duration,
    },
    /// 拒绝请求
    Reject {
        /// 拒绝原因
        reason: String,
    },
}

/// 资源感知调度策略
pub struct ResourceAwarePolicy {
    /// 策略配置
    config: ResourceAwarePolicyConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourceAwarePolicyConfig {
    /// 内存权重
    pub memory_weight: f64,
    /// CPU权重
    pub cpu_weight: f64,
    /// 磁盘权重
    pub disk_weight: f64,
    /// 网络权重
    pub network_weight: f64,
    /// 负载阈值
    pub load_threshold: f64,
}

impl Default for ResourceAwarePolicyConfig {
    fn default() -> Self {
        Self {
            memory_weight: 0.4,
            cpu_weight: 0.3,
            disk_weight: 0.2,
            network_weight: 0.1,
            load_threshold: 0.8,
        }
    }
}

impl ResourceAwarePolicy {
    pub fn new() -> Self {
        Self {
            config: ResourceAwarePolicyConfig::default(),
        }
    }

    /// 计算资源评分
    fn calculate_resource_score(&self, request: &ResourceRequirements, available: &ResourceRequirements) -> f64 {
        let memory_score = if available.memory_mb >= request.memory_mb {
            (available.memory_mb - request.memory_mb) as f64 / available.memory_mb as f64
        } else {
            0.0
        };

        let cpu_score = if available.cpu_cores >= request.cpu_cores {
            (available.cpu_cores - request.cpu_cores) as f64 / available.cpu_cores as f64
        } else {
            0.0
        };

        let disk_score = if available.disk_mb >= request.disk_mb {
            (available.disk_mb - request.disk_mb) as f64 / available.disk_mb as f64
        } else {
            0.0
        };

        let network_score = if available.network_bandwidth_mbps >= request.network_bandwidth_mbps {
            (available.network_bandwidth_mbps - request.network_bandwidth_mbps) as f64 / available.network_bandwidth_mbps as f64
        } else {
            0.0
        };

        memory_score * self.config.memory_weight +
        cpu_score * self.config.cpu_weight +
        disk_score * self.config.disk_weight +
        network_score * self.config.network_weight
    }
}

#[async_trait]
impl SchedulingPolicy for ResourceAwarePolicy {
    fn name(&self) -> &str {
        "resource_aware"
    }

    fn description(&self) -> &str {
        "基于资源使用情况和可用性的智能调度策略"
    }

    async fn make_decision(&self, context: &SchedulingContext) -> PolicyDecision {
        let start_time = std::time::Instant::now();

        // 检查系统负载
        if context.current_load > self.config.load_threshold {
            return PolicyDecision {
                action: SchedulingAction::Queue {
                    estimated_wait_time: Duration::from_secs(30),
                },
                confidence: 0.9,
                reason: "系统负载过高，建议排队等待".to_string(),
                alternatives: vec![
                    SchedulingAction::Reject {
                        reason: "系统负载超限".to_string(),
                    }
                ],
                decision_time: start_time.elapsed(),
            };
        }

        // 根据优先级选择池类型
        let preferred_pools = match context.request.priority {
            Priority::Critical => vec![PoolType::Hot],
            Priority::High => vec![PoolType::Hot, PoolType::Warm],
            Priority::Normal => vec![PoolType::Warm, PoolType::Hot, PoolType::Cold],
            Priority::Low => vec![PoolType::Cold, PoolType::Warm],
        };

        // 选择最佳池类型
        let selected_pool = preferred_pools.first().unwrap_or(&PoolType::Warm);

        PolicyDecision {
            action: SchedulingAction::Allocate {
                pool_type: *selected_pool,
                node_preference: None,
            },
            confidence: 0.8,
            reason: format!("基于{}优先级选择{}池", format!("{:?}", context.request.priority), match selected_pool {
                PoolType::Hot => "热",
                PoolType::Warm => "温",
                PoolType::Cold => "冷",
            }),
            alternatives: preferred_pools[1..].iter().map(|pool| SchedulingAction::Allocate {
                pool_type: *pool,
                node_preference: None,
            }).collect(),
            decision_time: start_time.elapsed(),
        }
    }

    fn priority(&self) -> u32 {
        200
    }
}

/// 优先级调度策略
pub struct PriorityPolicy {
    config: PriorityPolicyConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PriorityPolicyConfig {
    /// 高优先级配额
    pub high_priority_quota: f64,
    /// 普通优先级配额
    pub normal_priority_quota: f64,
    /// 低优先级配额
    pub low_priority_quota: f64,
}

impl Default for PriorityPolicyConfig {
    fn default() -> Self {
        Self {
            high_priority_quota: 0.3,
            normal_priority_quota: 0.5,
            low_priority_quota: 0.2,
        }
    }
}

impl PriorityPolicy {
    pub fn new() -> Self {
        Self {
            config: PriorityPolicyConfig::default(),
        }
    }
}

#[async_trait]
impl SchedulingPolicy for PriorityPolicy {
    fn name(&self) -> &str {
        "priority"
    }

    fn description(&self) -> &str {
        "基于请求优先级的调度策略"
    }

    async fn make_decision(&self, context: &SchedulingContext) -> PolicyDecision {
        let start_time = std::time::Instant::now();

        let (pool_type, confidence, reason) = match context.request.priority {
            Priority::Critical => (
                PoolType::Hot,
                0.95,
                "关键优先级请求，必须分配热池沙箱".to_string(),
            ),
            Priority::High => (
                PoolType::Hot,
                0.9,
                "高优先级请求，分配热池沙箱".to_string(),
            ),
            Priority::Normal => (
                PoolType::Warm,
                0.8,
                "普通优先级请求，分配温池沙箱".to_string(),
            ),
            Priority::Low => (
                PoolType::Cold,
                0.7,
                "低优先级请求，分配冷池沙箱".to_string(),
            ),
        };

        PolicyDecision {
            action: SchedulingAction::Allocate {
                pool_type,
                node_preference: None,
            },
            confidence,
            reason,
            alternatives: Vec::new(),
            decision_time: start_time.elapsed(),
        }
    }

    fn priority(&self) -> u32 {
        150
    }
}

/// 负载均衡调度策略
pub struct LoadBalancePolicy {
    config: LoadBalancePolicyConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoadBalancePolicyConfig {
    /// 负载均衡阈值
    pub balance_threshold: f64,
    /// 最大负载差异
    pub max_load_difference: f64,
}

impl Default for LoadBalancePolicyConfig {
    fn default() -> Self {
        Self {
            balance_threshold: 0.7,
            max_load_difference: 0.3,
        }
    }
}

impl LoadBalancePolicy {
    pub fn new() -> Self {
        Self {
            config: LoadBalancePolicyConfig::default(),
        }
    }
}

#[async_trait]
impl SchedulingPolicy for LoadBalancePolicy {
    fn name(&self) -> &str {
        "load_balance"
    }

    fn description(&self) -> &str {
        "基于系统负载均衡的调度策略"
    }

    async fn make_decision(&self, context: &SchedulingContext) -> PolicyDecision {
        let start_time = std::time::Instant::now();

        // 简化的负载均衡逻辑
        let pool_type = if context.current_load < self.config.balance_threshold {
            PoolType::Hot
        } else {
            PoolType::Warm
        };

        PolicyDecision {
            action: SchedulingAction::Allocate {
                pool_type,
                node_preference: None,
            },
            confidence: 0.8,
            reason: format!(
                "基于当前负载{:.2}选择{}池",
                context.current_load,
                match pool_type {
                    PoolType::Hot => "热",
                    PoolType::Warm => "温",
                    PoolType::Cold => "冷",
                }
            ),
            alternatives: Vec::new(),
            decision_time: start_time.elapsed(),
        }
    }

    fn priority(&self) -> u32 {
        120
    }
}

/// 语言特化调度策略
pub struct LanguageSpecificPolicy {
    language_configs: HashMap<Language, LanguageConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LanguageConfig {
    /// 首选池类型
    pub preferred_pool: PoolType,
    /// 最小资源需求
    pub min_resources: ResourceRequirements,
    /// 启动时间预期
    pub expected_startup_time: Duration,
}

impl Default for LanguageConfig {
    fn default() -> Self {
        Self {
            preferred_pool: PoolType::Warm,
            min_resources: ResourceRequirements {
                memory_mb: 256,
                cpu_cores: 1,
                disk_mb: 512,
                network_enabled: true,
                network_bandwidth_mbps: 10,
            },
            expected_startup_time: Duration::from_secs(5),
        }
    }
}

impl LanguageSpecificPolicy {
    pub fn new() -> Self {
        let mut language_configs = HashMap::new();

        // Python配置：内存需求较高
        language_configs.insert(Language::Python, LanguageConfig {
            preferred_pool: PoolType::Warm,
            min_resources: ResourceRequirements {
                memory_mb: 512,
                cpu_cores: 1,
                disk_mb: 1024,
                network_enabled: true,
                network_bandwidth_mbps: 10,
            },
            expected_startup_time: Duration::from_secs(3),
        });

        // JavaScript配置：启动快
        language_configs.insert(Language::JavaScript, LanguageConfig {
            preferred_pool: PoolType::Hot,
            min_resources: ResourceRequirements {
                memory_mb: 256,
                cpu_cores: 1,
                disk_mb: 512,
                network_enabled: true,
                network_bandwidth_mbps: 10,
            },
            expected_startup_time: Duration::from_secs(1),
        });

        // Java配置：启动慢，内存需求高
        language_configs.insert(Language::Java, LanguageConfig {
            preferred_pool: PoolType::Warm,
            min_resources: ResourceRequirements {
                memory_mb: 1024,
                cpu_cores: 2,
                disk_mb: 2048,
                network_enabled: true,
                network_bandwidth_mbps: 20,
            },
            expected_startup_time: Duration::from_secs(10),
        });

        Self { language_configs }
    }
}

#[async_trait]
impl SchedulingPolicy for LanguageSpecificPolicy {
    fn name(&self) -> &str {
        "language_specific"
    }

    fn description(&self) -> &str {
        "基于编程语言特性的专门调度策略"
    }

    async fn make_decision(&self, context: &SchedulingContext) -> PolicyDecision {
        let start_time = std::time::Instant::now();

        let default_config = LanguageConfig::default();
        let language_config = self.language_configs.get(&context.request.language)
            .unwrap_or(&default_config);

        // 检查资源需求是否满足
        let meets_min_requirements = context.request.resource_requirements.memory_mb >= language_config.min_resources.memory_mb
            && context.request.resource_requirements.cpu_cores >= language_config.min_resources.cpu_cores;

        if !meets_min_requirements {
            return PolicyDecision {
                action: SchedulingAction::Reject {
                    reason: format!(
                        "{}语言最低资源需求不满足：需要内存{}MB，CPU{}核心",
                        context.request.language,
                        language_config.min_resources.memory_mb,
                        language_config.min_resources.cpu_cores
                    ),
                },
                confidence: 0.95,
                reason: "资源需求不满足语言最低要求".to_string(),
                alternatives: Vec::new(),
                decision_time: start_time.elapsed(),
            };
        }

        PolicyDecision {
            action: SchedulingAction::Allocate {
                pool_type: language_config.preferred_pool,
                node_preference: None,
            },
            confidence: 0.85,
            reason: format!(
                "基于{}语言特性选择{}池",
                context.request.language,
                match language_config.preferred_pool {
                    PoolType::Hot => "热",
                    PoolType::Warm => "温",
                    PoolType::Cold => "冷",
                }
            ),
            alternatives: Vec::new(),
            decision_time: start_time.elapsed(),
        }
    }

    fn priority(&self) -> u32 {
        180
    }

    fn supports_language(&self, language: &Language) -> bool {
        self.language_configs.contains_key(language)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Instant;
    use uuid::Uuid;

    fn create_test_context() -> SchedulingContext {
        SchedulingContext {
            request: SchedulingRequest {
                request_id: Uuid::new_v4(),
                language: Language::Python,
                version: "3.9".to_string(),
                resource_requirements: ResourceRequirements {
                    memory_mb: 512,
                    cpu_cores: 1,
                    disk_mb: 1024,
                    network_enabled: true,
                    network_bandwidth_mbps: 10,
                },
                priority: Priority::Normal,
                timeout_secs: 300,
                affinity_constraints: None,
                policy_preference: None,
                metadata: HashMap::new(),
                request_time: Instant::now(),
            },
            available_resources: HashMap::new(),
            current_load: 0.5,
            node_constraints: Vec::new(),
        }
    }

    #[tokio::test]
    async fn test_resource_aware_policy() {
        let policy = ResourceAwarePolicy::new();
        let context = create_test_context();

        let decision = policy.make_decision(&context).await;
        assert!(matches!(decision.action, SchedulingAction::Allocate { .. }));
        assert!(decision.confidence > 0.0);
    }

    #[tokio::test]
    async fn test_priority_policy() {
        let policy = PriorityPolicy::new();
        let context = create_test_context();

        let decision = policy.make_decision(&context).await;
        if let SchedulingAction::Allocate { pool_type, .. } = decision.action {
            assert_eq!(pool_type, PoolType::Warm); // Normal priority -> Warm pool
        } else {
            panic!("Expected Allocate action");
        }
    }

    #[tokio::test]
    async fn test_load_balance_policy() {
        let policy = LoadBalancePolicy::new();
        let context = create_test_context();

        let decision = policy.make_decision(&context).await;
        assert!(matches!(decision.action, SchedulingAction::Allocate { .. }));
    }

    #[tokio::test]
    async fn test_language_specific_policy() {
        let policy = LanguageSpecificPolicy::new();
        let context = create_test_context();

        let decision = policy.make_decision(&context).await;
        if let SchedulingAction::Allocate { pool_type, .. } = decision.action {
            assert_eq!(pool_type, PoolType::Warm); // Python -> Warm pool
        } else {
            panic!("Expected Allocate action");
        }

        assert!(policy.supports_language(&Language::Python));
        assert!(policy.supports_language(&Language::Java));
    }

    #[tokio::test]
    async fn test_high_load_queueing() {
        let policy = ResourceAwarePolicy::new();
        let mut context = create_test_context();
        context.current_load = 0.9; // High load

        let decision = policy.make_decision(&context).await;
        assert!(matches!(decision.action, SchedulingAction::Queue { .. }));
    }
}